﻿/*
 * Copyright 2011 Hanns Kucer
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
using System.Collections.Generic;
using System.Threading;

public class ThreadSafeQueue<T>
{
	private Queue<T> q;

	public ThreadSafeQueue()
	{
		q = new Queue<T>();
	}

	public void Enqueue(T item)
	{
		lock (q)
			q.Enqueue(item);
	}

	public bool IsEmpty
	{
		get
		{
			lock (q)
				return (q.Count == 0);
		}
	}

	public T Dequeue()
	{
		lock (q)
		{
			if (q.Count > 0)
				return q.Dequeue();
		}

		return default(T);
	}
}

public class ThreadSafeCollection<T> : System.Collections.IEnumerable
{
	private Dictionary<T, object> dic;

	public ThreadSafeCollection()
	{
		dic = new Dictionary<T, object>();
	}

	public uint Count
	{
		get
		{
			lock (dic)
				return (uint)dic.Count;
		}
	}

	public void Add(T item)
	{
		lock (dic)
			dic.Add(item, null);
	}

	public void Remove(T item)
	{
		lock (dic)
			dic.Remove(item);
	}

	public T[] Keys
	{
		get
		{
			lock (dic)
			{
				T[] keys = new T[dic.Count];
				dic.Keys.CopyTo(keys, 0);
				return keys;
			}
		}
	}

	public System.Collections.IEnumerator GetEnumerator()
	{
		lock (dic)
			foreach (T item in dic.Keys)
				yield return item;
	}
}

public class MonitoredThreadSafeQueue<T>
{
	private Queue<T> queue;
	private int size = int.MaxValue;

	public MonitoredThreadSafeQueue()
	{
		queue = new Queue<T>();
	}

	public MonitoredThreadSafeQueue(int size)
	{
		this.size = size;
		queue = new Queue<T>();
	}

	public virtual void Enqueue(T item)
	{
		lock (queue)
		{
			while (queue.Count == size)
				Monitor.Wait(queue);

			queue.Enqueue(item);

			if (queue.Count == 1)
				Monitor.PulseAll(queue);
		}
	}

	public virtual bool IsEmpty
	{
		get
		{
			lock (queue)
				return (queue.Count == 0);
		}
	}

	public virtual T Dequeue()
	{
		lock (queue)
		{
			while (queue.Count == 0)
				Monitor.Wait(queue);

			T item = queue.Dequeue();

			if (queue.Count == size - 1)
				Monitor.PulseAll(queue);

			return item;
		}
	}
}
